#include "Game/CellFace.h"

namespace PocketSurvival
{
    static const int32_t oppositeFaces[6] = {2,3,0,1,5,4};
    static const Point3 faceToPoint3[6] = {
        Point3{ 0,  0,  1 },
        Point3{ 1,  0,  0 },
        Point3{ 0,  0, -1 },
        Point3{ -1, 0,  0 },
        Point3{ 0,  1,  0 },
        Point3{ 0, -1,  0 }
    };
    static const Vector3 faceToVector3[6] = {
        Vector3{ 0.0f,  0.0f,  1.0f  },
        Vector3{ 1.0f,  0.0f,  0.0f  },
        Vector3{ 0.0f,  0.0f,  -1.0f },
        Vector3{ -1.0f, 0.0f,  0.0f  },
        Vector3{ 0.0f,  1.0f,  0.0f  },
        Vector3{ 0.0f, -1.0f,  0.0f  }
    };

    Plane CellFace::calculatePlane() const
    {
        switch (face)
        {
        case 0:
            return Plane(Vector3{0.0f, 0.0f, 1.0f}, -(point.posZ + 1));
        case 1:
            return Plane(Vector3{-1.0f, 0.0f, 0.0f}, point.posX + 1);
        case 2:
            return Plane(Vector3{0.0f, 0.0f, -1.0f}, point.posZ);
        case 3:
            return Plane(Vector3{1.0f, 0.0f, 0.0f}, -point.posX);
        case 4:
            return Plane(Vector3{0.0f, 1.0f, 0.0f}, -(point.posY + 1));
        default:
            return Plane(Vector3{0.0f, -1.0f, 0.0f}, point.posY);
        }
    }


    int32_t CellFace::OppositeFace(int32_t face)
    {
        return oppositeFaces[face];
    }
    Point3 CellFace::FaceToPoint3(int32_t face)
    {
        return faceToPoint3[face];
    }
    Vector3 CellFace::FaceToVector3(int32_t face)
    {
        return faceToVector3[face];
    }
    int32_t CellFace::Point3ToFace(Point3 point, int32_t maxFace)
    {
        maxFace = MathUtils::Clamp<int32_t>(maxFace, 0 , 5);
        for(int index = 0; index < maxFace; index++)
        {
            if(faceToPoint3[index] == point)
            {
                return index;
            }
        }
        throw std::logic_error("Invalid Point3.");
    }
    int32_t CellFace::Vector3ToFace(Vector3 vector, int32_t maxFace)
    {
		maxFace = MathUtils::Clamp<int32_t>(maxFace, 0, 5);
		float num = 0.0f;
		int result = 0;
		for (int i = 0; i <= maxFace; i++)
		{
			float num2 = Vector3::Dot(faceToVector3[i], vector);
			if (num2 > num)
			{
				result = i;
				num = num2;
			}
		}
		return result;
    }
    CellFace CellFace::FromAxisAndDirection(int32_t x, int32_t y, int32_t z, int32_t axis, float direction)
    {
		CellFace result{0,0,0,0};
        result.point.posX = x;
        result.point.posY = y;
        result.point.posZ = z;
		switch (axis)
		{
		case 0:
			result.face = (direction > 0.0f) ? 1 : 3;
			break;
		case 1:
			result.face = (direction > 0.0f) ? 4 : 5;
			break;
		case 2:
			result.face = (!(direction > 0.0f)) ? 2 : 0;
			break;
		}
		return result;
    }

}
